package FlowGram.Application.Parser.Actions.Control;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import FlowGram.Application.Application;
import FlowGram.Application.Parser.FinchParser;
import FlowGram.Application.Parser.FinchParserException;
import FlowGram.Application.Parser.FinchProgramFlow;
import FlowGram.Application.Parser.Controllers.FinchController;
import FlowGram.Application.Parser.Prototype.FinchParserPrototype;
import FlowGram.Application.Parser.Utility.Configuration;

public class Include extends ControlAction {

	
	protected String filepath;
	
	
	public Include(FinchParser parser) {
		super(parser);
	}

	public Include() {
		super();
	}
	
	public static boolean matches(String s){
		return s.matches("^include.+");
	}
	public static boolean matchsEnd(String s){
		return s.matches("^end$");
	}
	public static String syntax(){
		return "include <file>";
	}
	

	@Override
	public String toCode(int indent) {
		return "include "+this.filepath;
	}
	@Override
	public String toHTML(String idPrefix) {
		return this.toCode();
	}

	@Override
	public void execute(FinchController controller) {
		this.ensureController(controller);
		this.innerFlow.execute();
	}

	@Override
	public String logMessage() {
		return "including file \""+this.filepath+"\"";
	}

	@Override
	public void parse(String statement) throws FinchParserException {
		Pattern p = Pattern.compile("^include\\s+(.+)$");
		Matcher matcher = p.matcher(statement);
		while(matcher.find()){
			if(matcher.group(1) != null){
				this.filepath = matcher.group(1);
				String programBuffer = "";
				try {
				    BufferedReader in = new BufferedReader(findFile(this.filepath));
				    String str;
				    while ((str = in.readLine()) != null) {
				        programBuffer += str+"\n";
				    }
				    in.close();
				}catch(FileNotFoundException e){
					System.out.println(e.getMessage());
					continue;
				}catch (IOException e) {
					System.out.println("Error reading file.");
					continue;
				}
				this.innerFlow = parser.Parse(programBuffer);
				
			}	
		}
	}

	
	
	
	protected static FileReader findFile(String path) throws FileNotFoundException{
		ArrayList<String> includepath = getIncludePaths();
		includepath.add(0, "");
		
		int currPath = 0;
		FileReader fr;
		while(currPath < includepath.size()){
			try{
				fr = getFile(includepath.get(currPath)+path);
				return fr;
			}catch(FileNotFoundException e){
				currPath++;
				continue;
			}
		}
		throw new FileNotFoundException("Could not find file '"+path+"'");
	}
	protected static FileReader getFile(String path) throws FileNotFoundException{
		//System.out.println("attempting to open '"+path+"'");
		FileReader r = null;
		try {
			r = new FileReader(URLDecoder.decode(path, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
		return r;
	}
	protected static ArrayList<String> getIncludePaths(){
		ArrayList<String> includepaths = new ArrayList<String>();
		Configuration config;
		try{
			config = Configuration.getInstance();
		}catch(Exception e){
			return includepaths;
		}
		String appPath = getApplicationPath();
		if(appPath.endsWith("/")){
			appPath = appPath.substring(0, appPath.length()-1);
		}
		if(appPath.startsWith("/")){
			appPath = appPath.substring(1);
		}
		String workspace = Application.getInstance().getWorkspace();
		String[] paths = config.config.getStringArray("includepaths.path");
		for(int i=0; i < paths.length; i++){
			
			String path = paths[i].replaceAll("\\$\\{finchpath\\}", Matcher.quoteReplacement(appPath));
			path = path.replaceAll("\\$\\{workspace\\}", Matcher.quoteReplacement(workspace));
			includepaths.add(path);
		}
		includepaths.add(Application.getInstance().getCurrentProjectPath()+File.separator);
		return includepaths;
	}
	protected static String getApplicationPath(){
		String applicationDir = FinchParserPrototype.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 
		return applicationDir;
	}
}
